package com.gobang.common.service;

import com.gobang.common.constant.BusinessErrorCode;
import com.gobang.common.exception.BusinessException;
import com.gobang.util.JwtUtil;
import lombok.RequiredArgsConstructor;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

/**
 * Token认证服务
 * 统一封装 JWT + Redis 双重校验逻辑，供 HTTP 与 WebSocket 使用。
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class TokenAuthService {

    private final JwtUtil jwtUtil;

    /**
     * 校验 Token 是否有效，并返回认证用户信息。
     *
     * @param token JWT Token
     * @return 认证用户信息
     */
    public AuthUser validateToken(String token) {
        if (!StringUtils.hasText(token)) {
            throw new BusinessException(BusinessErrorCode.TOKEN_MISSING, "Token缺失");
        }

        // 1. 校验 JWT 本身是否有效（签名、格式、过期时间）
        if (!jwtUtil.validateToken(token)) {
            throw new BusinessException(BusinessErrorCode.TOKEN_INVALID, "Token无效或已过期");
        }

        // 2. Redis 中二次校验：确保 Token 处于登录有效状态
        if (!jwtUtil.isTokenValidInRedis(token)) {
            // JWT 有效但 Redis 中不存在，视为已登出或失效
            throw new BusinessException(BusinessErrorCode.TOKEN_INVALID, "Token已失效，请重新登录");
        }

        Long userId = jwtUtil.getUserIdFromToken(token);
        String username = jwtUtil.getUsernameFromToken(token);
        String role = jwtUtil.getRoleFromToken(token);

        if (userId == null || !StringUtils.hasText(username) || !StringUtils.hasText(role)) {
            log.warn("Token解析出的用户信息不完整: userId={}, username={}, role={}", userId, username, role);
            throw new BusinessException(BusinessErrorCode.TOKEN_INVALID, "Token中用户信息不完整");
        }

        return new AuthUser(userId, username, role);
    }

    /**
     * 认证用户信息
     */
    @Value
    public static class AuthUser {
        Long userId;
        String username;
        String role;
    }
}
